/*
 * FreeModbus Libary: user callback functions and buffer define in master mode
 * Copyright (C) 2013 Armink <armink.ztl@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * File: $Id: user_mb_app_m.c,v 1.60 2013/11/23 11:49:05 Armink $
 */
#include "user_mb_app.h"

/*-----------------------Master mode use these variables----------------------*/
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
// Master mode:DiscreteInputs variables
USHORT usMDiscInStart = M_DISCRETE_INPUT_START;
#if M_DISCRETE_INPUT_NDISCRETES % 8
UCHAR ucMDiscInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_DISCRETE_INPUT_NDISCRETES / 8 + 1];
#else
UCHAR ucMDiscInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_DISCRETE_INPUT_NDISCRETES / 8];
#endif
// Master mode:Coils variables
USHORT usMCoilStart = M_COIL_START;
#if M_COIL_NCOILS % 8
UCHAR ucMCoilBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_COIL_NCOILS / 8 + 1];
#else
UCHAR ucMCoilBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_COIL_NCOILS / 8]; // 线圈数量/8很正常
#endif
// Master mode:InputRegister variables
USHORT usMRegInStart = M_REG_INPUT_START; // 这个是干啥的????
USHORT usMRegInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_INPUT_NREGS]; // 16行  100列  //输入寄存器
// Master mode:HoldingRegister variables
USHORT usMRegHoldStart = M_REG_HOLDING_START;
USHORT usMRegHoldBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_HOLDING_NREGS]; // 保持寄存器

/**
 * Modbus master input register callback function.
 *
 * @param pucRegBuffer input register buffer  //指向返回的数据域的开始位置
 * @param usAddress input register address    //寄存器的开始地址  0x0000 ~ 0xFFFF
 * @param usNRegs input register number       //寄存器的数量     0x0001 ~ 0x007D (1~125)
 *
 * @return result
 */
eMBErrorCode eMBMasterRegInputCB(UCHAR* pucRegBuffer, USHORT usAddress, USHORT usNRegs)
{
    eMBErrorCode eStatus = MB_ENOERR;
    USHORT iRegIndex;
    USHORT* pusRegInputBuf;
    USHORT REG_INPUT_START;
    USHORT REG_INPUT_NREGS;
    USHORT usRegInStart;

    pusRegInputBuf = usMRegInBuf[ucMBMasterGetDestAddress() - 1]; // 每个从站会使用100个uint16_t类型的变量
    REG_INPUT_START = M_REG_INPUT_START;
    REG_INPUT_NREGS = M_REG_INPUT_NREGS;
    usRegInStart = usMRegInStart; // 这里是0   这个相当于地址偏移量

    /* it already plus one in modbus function method. */
    usAddress--;

    if ((usAddress >= REG_INPUT_START) && (usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS)) { // 要读取的寄存器地址在正确的范围内   开始地址合法&&结束地址合法
        iRegIndex = usAddress - usRegInStart; // 相当于 usAddress - 0()
        while (usNRegs > 0) { // pusRegInputBuf相当于全映射,但只是用到了需要的部分
            pusRegInputBuf[iRegIndex] = *pucRegBuffer++ << 8; // 返回的寄存器的高字节
            pusRegInputBuf[iRegIndex] |= *pucRegBuffer++; // 返回的寄存器的低字节
            iRegIndex++; // 这里是将
            usNRegs--;
        }
    } else {
        eStatus = MB_ENOREG;
    }

    return eStatus;
}

/**
 * Modbus master holding register callback function.
 *
 * @param pucRegBuffer holding register buffer  //指向返回的数据域的开始位置
 * @param usAddress holding register address    //寄存器的开始地址  0x0000 ~ 0xFFFF
 * @param usNRegs holding register number       //寄存器的数量      0x0001 ~ 0x007D (1~125)
 * @param eMode read or write
 *
 * @return result
 */
eMBErrorCode eMBMasterRegHoldingCB(UCHAR* pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode)
{
    eMBErrorCode eStatus = MB_ENOERR;

    USHORT iRegIndex;
    USHORT* pusRegHoldingBuf;
    USHORT REG_HOLDING_START;
    USHORT REG_HOLDING_NREGS;
    USHORT usRegHoldStart;

    pusRegHoldingBuf = usMRegHoldBuf[ucMBMasterGetDestAddress() - 1]; // 每个从站会使用100个uint16_t类型的变量
    REG_HOLDING_START = M_REG_HOLDING_START;
    REG_HOLDING_NREGS = M_REG_HOLDING_NREGS;
    usRegHoldStart = usMRegHoldStart; // 目前为0
    /* if mode is read, the master will write the received date to buffer. */
    eMode = MB_REG_WRITE; // 当为MB_REG_READ时,其实没用

    /* it already plus one in modbus function method. */
    usAddress--;

    if ((usAddress >= REG_HOLDING_START) && (usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS)) {
        // 表示没有越界  REG_HOLDING_START + REG_HOLDING_NREGS 这个地址没有存东西
        iRegIndex = usAddress - usRegHoldStart; // 直接等于usAddress

        switch (eMode) {
            /* read current register values from the protocol stack. */
        case MB_REG_READ: // 这里是不会执行的
            while (usNRegs > 0) {
                *pucRegBuffer++ = (UCHAR)(pusRegHoldingBuf[iRegIndex] >> 8); // 将寄存器数据往外搬运
                *pucRegBuffer++ = (UCHAR)(pusRegHoldingBuf[iRegIndex] & 0xFF);
                iRegIndex++;
                usNRegs--;
            }
            break;
            /* write current register values with new values from the protocol stack. */
        case MB_REG_WRITE:
            while (usNRegs > 0) {
                pusRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
                pusRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
                iRegIndex++;
                usNRegs--;
            }
            break;
        }
    } else {
        eStatus = MB_ENOREG;
    }

    return eStatus;
}

/**
 * Modbus master coils callback function.
 *
 * @param pucRegBuffer coils buffer  指向外部的数据
 * @param usAddress coils address  //这里是指开始地址吗？？
 * @param usNCoils coils number
 * @param eMode read or write  read时表示pucRegBuffer出  write时表示pucRegBuffer入
 *
 * @return result
 */
eMBErrorCode eMBMasterRegCoilsCB(UCHAR* pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode)
{
    eMBErrorCode eStatus = MB_ENOERR;
    USHORT iRegIndex, iRegBitIndex, iNReg;
    UCHAR* pucCoilBuf; //
    USHORT COIL_START;
    USHORT COIL_NCOILS;
    USHORT usCoilStart;
    iNReg = usNCoils / 8 + 1; // 实参传进来之前,已经做了检查确保其大于0  得考虑当usNCoils为8时,有iNReg = 8/8 + 1=2  会不会有bug

    // if ((usCoilCount % 8) != 0) { // 111=0x07  相当于(usCoilCount % 8) != 0
    //     ucByteCount = (UCHAR)(usCoilCount / 8 + 1); // 最后一个字节会有剩余空间
    // } else {
    //     // 这表示线圈数量是8的个数
    //     ucByteCount = (UCHAR)(usCoilCount / 8);
    // } // 一个线圈一bit,计算有多少个字节

    pucCoilBuf = ucMCoilBuf[ucMBMasterGetDestAddress() - 1]; // 从机地址从1开始  注意ucMCoilBuf是一个二维数组
    COIL_START = M_COIL_START; //
    COIL_NCOILS = M_COIL_NCOILS; // 线圈数量64个
    usCoilStart = usMCoilStart; // 初始值为0

    /* if mode is read,the master will write the received date to buffer. */
    eMode = MB_REG_WRITE; // 我这里是读 MB_REG_READ

    /* it already plus one in modbus function method. */
    usAddress--;
    // usAddress这里是寄存器地址  // 起始地址大于等于0  modbus规定起始地址由两个字节构成0x0000-0xFFFF   线圈数量由2个字节构成,取值范围为0x0001~0x07D0 (1~2000)
    if ((usAddress >= COIL_START) && (usAddress + usNCoils <= COIL_START + COIL_NCOILS)) { // 线圈开始地址是对的,并且线圈最大地址没有越界
        // COIL_START + COIL_NCOILS  这个地址没有使用  最后的地址是   (COIL_START + COIL_NCOILS-1)
        iRegIndex = (USHORT)(usAddress - usCoilStart) / 8; // 0-7在0上  8-15在1上     这里是起始地址在哪个寄存器上(就是在哪个字节上 字节序号从0开始)

        iRegBitIndex = (USHORT)(usAddress - usCoilStart) % 8; // 在一个字节中的偏移   起始地址在寄存器中的偏移
        switch (eMode) {
            /* read current coil values from the protocol stack. */
        case MB_REG_READ: // 读取时的数据方向为   pucCoilBuf-->pucRegBuffer
            while (iNReg > 0) { // 这个循环执行iNReg次
                *pucRegBuffer++ = xMBUtilGetBits(&pucCoilBuf[iRegIndex++], iRegBitIndex, 8); // 返回以（iRegIndex*8+iRegBitIndex)开头的8个bit
                iNReg--; // 上面每次的效果都是一样的,不过每次会移动一字节
            }
            pucRegBuffer--; // 回原
            /* last coils */
            usNCoils = usNCoils % 8; // 线圈数量对8求余
            /* filling zero to high bit */
            *pucRegBuffer = *pucRegBuffer << (8 - usNCoils);
            *pucRegBuffer = *pucRegBuffer >> (8 - usNCoils); // 这里是干啥的？？？
            break;

            /* write current coil values with new values from the protocol stack. */
        case MB_REG_WRITE: // 写时的数据方向为  pucRegBuffer-->pucCoilBuf
            while (iNReg > 1) { // 循环执行iNReg-1次  这个设置函数有一个特点就是,可以从一个字节中的任意位开始设置
                xMBUtilSetBits(&pucCoilBuf[iRegIndex++], iRegBitIndex, 8, *pucRegBuffer++); // 数据流向是从哪里到哪里？？？应该改是从pucRegBuffer-->pucCoilBuf这里
                // pucCoilBuf[iRegIndex++]指明了线圈所在的字节  iRegBitIndex指明线圈在一个字节中的位置 0~7   8个线圈一写
                iNReg--; // pucRegBuffer是干啥的？？   iRegBitIndex:在一个字节中的偏移
            } //
            /* last coils    此时 iNReg==1*/
            usNCoils = usNCoils % 8; // 最后几个线圈(一个字节装不满)
            /* xMBUtilSetBits has bug when ucNBits is zero */
            if (usNCoils != 0) { // 这里相当于将usNCoils = usNCoils % 8 个bit贴上值  上面是8个bit贴上值
                xMBUtilSetBits(&pucCoilBuf[iRegIndex++], iRegBitIndex, usNCoils, *pucRegBuffer++);
            }
            break;
        }
    } else { // MB_ENOERR
        eStatus = MB_ENOREG;
    }
    return eStatus;
}

/**
 * Modbus master discrete callback function.
 *
 * @param pucRegBuffer discrete buffer
 * @param usAddress discrete address
 * @param usNDiscrete discrete number
 *
 * @return result
 */
eMBErrorCode eMBMasterRegDiscreteCB(UCHAR* pucRegBuffer, USHORT usAddress, USHORT usNDiscrete)
{
    eMBErrorCode eStatus = MB_ENOERR;
    USHORT iRegIndex, iRegBitIndex, iNReg;
    UCHAR* pucDiscreteInputBuf;
    USHORT DISCRETE_INPUT_START;
    USHORT DISCRETE_INPUT_NDISCRETES;
    USHORT usDiscreteInputStart;
    iNReg = usNDiscrete / 8 + 1;

    pucDiscreteInputBuf = ucMDiscInBuf[ucMBMasterGetDestAddress() - 1];
    DISCRETE_INPUT_START = M_DISCRETE_INPUT_START;
    DISCRETE_INPUT_NDISCRETES = M_DISCRETE_INPUT_NDISCRETES;
    usDiscreteInputStart = usMDiscInStart;

    /* it already plus one in modbus function method. */
    usAddress--;

    if ((usAddress >= DISCRETE_INPUT_START)
        && (usAddress + usNDiscrete <= DISCRETE_INPUT_START + DISCRETE_INPUT_NDISCRETES)) {
        iRegIndex = (USHORT)(usAddress - usDiscreteInputStart) / 8;
        iRegBitIndex = (USHORT)(usAddress - usDiscreteInputStart) % 8;

        /* write current discrete values with new values from the protocol stack. */
        while (iNReg > 1) {
            xMBUtilSetBits(&pucDiscreteInputBuf[iRegIndex++], iRegBitIndex, 8,
                *pucRegBuffer++);
            iNReg--;
        }
        /* last discrete */
        usNDiscrete = usNDiscrete % 8;
        /* xMBUtilSetBits has bug when ucNBits is zero */
        if (usNDiscrete != 0) {
            xMBUtilSetBits(&pucDiscreteInputBuf[iRegIndex++], iRegBitIndex,
                usNDiscrete, *pucRegBuffer++);
        }
    } else {
        eStatus = MB_ENOREG;
    }

    return eStatus;
}
#endif
